<template>
  <div class="app-container">
    <div class="config-container">
      <!-- 左侧列：工艺路线绑定工序 -->
      <div class="left-panel">
        <div class="panel-header">
          <span>工序节点列表</span>
          <el-button type="primary" size="small" @click="showAddDialog">添加</el-button>
        </div>
        <div class="node-list-container" v-loading="loading">
          <div v-if="nodeList.length === 0" class="empty-list">
            <el-empty description="暂无工序节点" size="small"/>
          </div>
          <div v-for="node in nodeList" :key="node.id"
               :class="['node-card', { 'node-card-selected': selectedNode && selectedNode.id === node.id }]"
               @click="selectNode(node)">
            <div class="node-header">
              <span class="node-code">{{ node.procedureCode }}</span>
              <div>
                <el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleEdit(node)" class="edit-btn">
                </el-button>
                <el-button size="mini" type="text" icon="el-icon-delete" style="color: #f00;"
                           @click.stop="handleDelete(node.id)" class="delete-btn">
                </el-button>
              </div>
            </div>
            <div class="node-content">
              <div class="node-title">{{ node.procedureName }}</div>
              <div class="node-description">{{ node.processNodeName }}</div>
            </div>
          </div>
        </div>
      </div>

      <!-- 右侧列：配置详情 -->
      <div class="right-panel">
        <div v-if="!selectedNode" class="empty-state">
          <el-empty description="请选择左侧工序节点进行配置"/>
        </div>
        <div v-else>
          <el-tabs v-model="activeTab">
            <el-tab-pane label="物料" name="material">
              <el-card class="material-card" shadow="never">
                <div v-loading="loadingMaterial" class="material-content">
                  <el-form :model="materialData" label-width="120px">
                    <!-- 基础信息 -->
                    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
                      <div class="section-title">基础信息</div>
                      <el-button type="primary" @click="saveMaterialConfig" :loading="saving">
                        保存配置
                      </el-button>
                    </div>
                    <el-row :gutter="20">
                      <el-col :span="6">
                        <el-form-item label="仓库">
                          <treeselect v-model="materialData.warehouseId" :options="warehouseTree"
                                      :normalizer="normalizerW" placeholder="选择仓库" style="width: 100%"
                                      @select="onWarehouseChange"/>
                        </el-form-item>
                      </el-col>
                      <el-col :span="6">
                        <el-form-item label="库位">
                          <el-select v-model="materialData.storageId" placeholder="请选择库位" clearable style="width: 100%">
                            <el-option v-for="location in locationList" :key="location.id"
                                       :label="location.storageLocationName" :value="location.id"/>
                          </el-select>
                        </el-form-item>
                      </el-col>
                      <el-col :span="6">
                        <el-form-item label="良率">
                          <el-input-number v-model="materialData.passRate" :min="0" :max="100" :precision="2"
                                           placeholder="请输入良率" style="width: 100%"/>
                        </el-form-item>
                      </el-col>
                    </el-row>

                    <!-- 产出物料 -->
                    <div class="section-title">产出物料</div>
                    <div class="out-material-section">
                      <el-row :gutter="20">
                        <el-col :span="6">
                          <el-form-item label="物料名称">
                            <el-select v-model="materialData.outMaterial.materialId" placeholder="选择物料" filterable
                                       remote :remote-method="getMaterialList" clearable
                                       @change="(val) => handleMaterialSelect(val, 'out')" style="width: 100%"
                                       :disabled="!materialData.outMaterial">
                              <el-option v-for="material in materialList" :key="material.id"
                                         :label="material.materialNo + '-' + material.materialName"
                                         :value="material.id"/>
                            </el-select>
                          </el-form-item>
                        </el-col>
                        <el-col :span="6">
                          <el-form-item label="转化率">
                            <el-input-number v-model="(materialData.outMaterial || {}).convertedRate" :min="0" :max="1"
                                             :precision="3" :step="0.001" style="width: 100%"/>
                          </el-form-item>
                        </el-col>
                      </el-row>
                    </div>


                    <!-- 投入物料列表和保存按钮的弹性布局容器 -->
                    <div style="display: flex; flex-direction: column; min-height: 600px;">
                      <!-- 列表标题和添加按钮 -->
                      <div
                        style="display: flex; justify-content: space-between; align-items: center; margin: 20px 0 10px 0;">
                        <div class="section-title">投入物料列表</div>
                        <el-button icon="el-icon-plus" type="primary" size="small" plain @click="addInMaterial">添加投入物料
                        </el-button>
                      </div>

                      <!-- 可滚动的物料表格区域 -->
                      <div style="flex: 1; overflow-y: auto; margin-bottom: 16px;">
                        <el-table :data="materialData.inMaterialList" border style="width: 100%;"
                                  :header-cell-style="{ background: '#f5f7fa' }" row-key="id">
                          <el-table-column type="index" label="序号" width="60" align="center"/>
                          <el-table-column prop="materialName" label="物料名称">
                            <template slot-scope="scope">
                              <el-select v-model="scope.row.materialId" placeholder="选择物料" filterable remote
                                         :remote-method="(query) => getMaterialList(query, scope.$index)" clearable
                                         @change="(val) => handleMaterialSelect(val, 'in', scope.$index)"
                                         style="width: 100%">
                                <el-option v-for="material in (scope.row.materialOptions || materialList)"
                                           :key="material.id" :label="material.materialNo + '-' + material.materialName"
                                           :value="material.id"/>
                              </el-select>
                            </template>
                          </el-table-column>
                          <el-table-column prop="convertedRate" label="转化率">
                            <template slot-scope="scope">
                              <el-input-number v-model="scope.row.convertedRate" :min="0" :max="1" :precision="3"
                                               :step="0.001"/>
                            </template>
                          </el-table-column>
                          <el-table-column prop="isMaster" label="主物料">
                            <template slot-scope="scope">
                              <el-switch v-model="scope.row.isMaster"
                                         @change="handleMasterChange(scope.row, scope.$index)"/>
                            </template>
                          </el-table-column>
                          <el-table-column label="操作" width="80" align="center">
                            <template slot-scope="scope">
                              <el-button type="danger" size="mini" @click="removeInMaterial(scope.$index)">
                                删除
                              </el-button>
                            </template>
                          </el-table-column>
                        </el-table>
                      </div>


                    </div>
                  </el-form>
                </div>
              </el-card>
            </el-tab-pane>
            <el-tab-pane label="质检" name="quality">
              <el-card class="quality-card" shadow="never" v-loading="loadingQuality">
                <div v-if="!selectedNode" class="empty-state">
                  <el-empty description="请选择左侧工序节点进行配置"/>
                </div>
                <div v-else>
                  <!-- 首件检配置 -->
                  <div class="quality-section">
                    <div class="section-header">
                      <h3>首件检</h3>
                      <div class="header-controls">
                        <el-switch v-model="qualityData.firstCheck" active-text="开启" inactive-text="关闭"
                                   @change="toggleQualityType('firstCheck')"/>
                        <el-button type="primary" size="small" @click="focusSchemeSelect('firstCheck')">
                          添加质检方案
                        </el-button>
                      </div>
                    </div>
                    <div>
                      <div class="scheme-selector" style="margin-bottom: 15px;">
                        <el-table :data="qualityData.firstQualityList" stripe style="width: 100%">
                          <el-table-column prop="inspectionSchemeName" label="质检方案名称"/>
                          <el-table-column label="操作" width="100" fixed="right">
                            <template slot-scope="scope">
                              <el-button size="mini" type="text" @click="deleteQualityScheme('firstCheck', scope.row.inspectionSchemeId)" icon="el-icon-delete"/>
                            </template>
                          </el-table-column>
                        </el-table>
                      </div>
                    </div>
                  </div>

                  <!-- 末件检配置 -->
                  <div class="quality-section">
                    <div class="section-header">
                      <h3>末件检</h3>
                      <div class="header-controls">
                        <el-switch v-model="qualityData.lastCheck" active-text="开启" inactive-text="关闭"
                                   @change="toggleQualityType('lastCheck')"/>
                        <el-button type="primary" size="small" @click="focusSchemeSelect('lastCheck')">
                          添加质检方案
                        </el-button>
                      </div>
                    </div>
                    <div>
                      <div class="scheme-selector" style="margin-bottom: 15px;">
                        <el-table :data="qualityData.lastQualityList" stripe style="width: 100%">
                          <el-table-column prop="inspectionSchemeName" label="质检方案名称"/>
                          <el-table-column label="操作" width="100" fixed="right">
                            <template slot-scope="scope">
                              <el-button size="mini" type="text" @click="deleteQualityScheme('lastCheck', scope.row.inspectionSchemeId)" icon="el-icon-delete"/>
                            </template>
                          </el-table-column>
                        </el-table>
                      </div>
                    </div>
                  </div>

                  <!-- 完工检配置 -->
                  <div class="quality-section">
                    <div class="section-header">
                      <h3>完工检</h3>
                      <div class="header-controls">
                        <el-switch v-model="qualityData.finishedCheck" active-text="开启" inactive-text="关闭"
                                   @change="toggleQualityType('finishedCheck')"/>
                        <el-button type="primary" size="small" @click="focusSchemeSelect('finishedCheck')">
                          添加质检方案
                        </el-button>
                      </div>
                    </div>
                    <div>
                      <div class="scheme-selector" style="margin-bottom: 15px;">
                        <el-table :data="qualityData.finishedQualityList" stripe style="width: 100%">
                          <el-table-column prop="inspectionSchemeName" label="质检方案名称"/>
                          <el-table-column label="操作" width="100" fixed="right">
                            <template slot-scope="scope">
                              <el-button size="mini" type="text" @click="deleteQualityScheme('finishedCheck', scope.row.inspectionSchemeId)" icon="el-icon-delete"/>
                            </template>
                          </el-table-column>
                        </el-table>
                      </div>
                    </div>
                  </div>

                  <!-- 巡检配置 -->
                  <div class="quality-section">
                    <div class="section-header">
                      <h3>巡检</h3>
                      <div class="header-controls">
                        <el-switch v-model="qualityData.scheduleCheck" active-text="开启" inactive-text="关闭"
                                   @change="toggleQualityType('scheduleCheck')"/>
                        <el-button type="primary" size="small" @click="focusSchemeSelect('scheduleCheck')">
                          添加质检方案
                        </el-button>
                      </div>
                    </div>
                    <div>
                      <div class="scheme-selector" style="margin-bottom: 15px;">
                        <el-table :data="qualityData.scheduleQualityList" stripe style="width: 100%">
                          <el-table-column prop="inspectionSchemeName" label="质检方案名称"/>
                          <el-table-column label="操作" width="100" fixed="right">
                            <template slot-scope="scope">
                              <el-button size="mini" type="text" @click="deleteQualityScheme('scheduleCheck', scope.row.inspectionSchemeId)" icon="el-icon-delete"/>
                            </template>
                          </el-table-column>
                        </el-table>
                      </div>
                    </div>
                  </div>
                </div>
              </el-card>
            </el-tab-pane>
            <el-tab-pane label="SOP" name="drawing">
              <el-card shadow="never">
                <div v-if="!selectedNode" class="empty-state">
                  <el-empty description="请选择左侧工序节点进行配置"/>
                </div>
                <div v-else>
                  <div style="margin-bottom: 10px;width: 100%;display: flex;justify-content: flex-end">
                    <el-button type="primary" @click="handleUploadSOP">上传文件</el-button>
                  </div>
                  <el-table :data="sopData" stripe style="width: 100%" max-height="500px">
                    <el-table-column prop="sopName" label="名称"/>
                    <el-table-column prop="remark" label="备注"/>
                    <el-table-column label="操作">
                      <template slot-scope="scope">
                        <el-button size="mini" type="primary" @click="handlePreviewSOP(scope.row)">预览</el-button>
                        <el-button size="mini" type="primary" @click="handleDownloadSOP(scope.row)">下载</el-button>
                        <el-button size="mini" type="danger" @click="handleDeleteSOP(scope.row)">删除</el-button>
                      </template>
                    </el-table-column>
                  </el-table>
                </div>
              </el-card>
            </el-tab-pane>
          </el-tabs>
        </div>
      </div>
    </div>

    <!-- SOP上传弹窗 -->
    <el-dialog :title="upload.title" :visible.sync="upload.open" width="600px" append-to-body>
      <el-form ref="sopForm" :model="sopForm" :rules="sopRules" label-width="80px">
        <el-form-item label="文件名称" prop="sopName">
          <el-input v-model="sopForm.sopName" placeholder="请输入文件名称"/>
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="sopForm.remark" placeholder="请输入备注" type="textarea" :rows="2"/>
        </el-form-item>
        <el-form-item label="文件">
          <el-upload ref="upload" :limit="1" :auto-upload="false" drag :headers="upload.headers" :action="upload.url"
                     :data="upload.data" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress"
                     :on-success="handleFileSuccess">
            <i class="el-icon-upload"></i>
            <div class="el-upload__text">
              将文件拖到此处，或 <em>点击上传</em>
            </div>
            <div class="el-upload__tip" slot="tip">支持所有格式文件上传</div>
          </el-upload>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitSopForm" :loading="upload.isUploading">确 定</el-button>
        <el-button @click="upload.open = false">取 消</el-button>
      </div>
    </el-dialog>

    <!-- 预览对话框 -->
    <el-dialog :title="'预览: ' + previewDialog.fileName" :visible.sync="previewDialog.open" width="95%" height="90vh"
               top="2vh"
               append-to-body>
      <div style="width: 100%; height: calc(80vh - 80px); overflow: hidden;">
        <!-- 使用@vue-office组件的文件预览方案 -->
        <div v-if="isImagePreview(previewDialog.fileUrl)"
             style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center;">
          <img :src="previewDialog.fileUrl" style="max-width: 100%; max-height: 100%; object-fit: contain;" alt="图片预览">
        </div>
        <div v-else-if="isTextPreview(previewDialog.fileUrl)"
             style="width: 100%; height: 100%; overflow: auto; padding: 10px; background: #f5f5f5;">
          <pre v-if="previewContent" style="margin: 0; white-space: pre-wrap; word-wrap: break-word;">{{
              previewContent
            }}</pre>
          <div v-else style="display: flex; justify-content: center; align-items: center; height: 100%;">
            加载中...
          </div>
        </div>
        <div v-else-if="isPdfPreview(previewDialog.fileUrl)" style="width: 100%; height: 100%; overflow: auto;">
          <!-- PDF文件使用vue-pdf组件预览 -->
          <pdf
            :src="getPreviewUrl(previewDialog.fileUrl)"
            style="width: 100%;"
            @num-pages="handlePdfNumPages"
            @page-loaded="handlePdfPageLoaded"
            @loaded="handlePdfLoaded"
          ></pdf>
        </div>
        <div v-else-if="isExcelPreview(previewDialog.fileUrl)" style="width: 100%; height: 100%; position: relative;">
          <!-- Excel文件使用vue-office-excel组件预览 -->
          <div v-if="excelLoading"
               style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 10;">
            <el-loading-text>正在加载Excel文件...</el-loading-text>
          </div>
          <vue-office-excel
            :src="getPreviewUrl(previewDialog.fileUrl)"
            style="width: 100%; height: 100%;"
            @rendered="renderedHandler"
            @error="handleExcelError"
            @load="excelLoading = true"
          />
        </div>
        <div v-else-if="isWordPreview(previewDialog.fileUrl)" style="width: 100%; height: 100%; position: relative;">
          <!-- Word文件使用vue-office-docx组件预览 -->
          <div v-if="wordLoading"
               style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 10;">
            <el-loading-spinner></el-loading-spinner>
            <el-loading-text>正在加载Word文件...</el-loading-text>
          </div>
          <vue-office-docx
            :src="getPreviewUrl(previewDialog.fileUrl)"
            style="width: 100%; height: 100%;"
            :options="{}"
            @rendered="handleDocxRendered"
            @error="handleDocxError"
            @load="handleDocxLoad"
          />
        </div>
        <div v-else style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center;">
          <!-- 不支持预览的文件类型 -->
          <div style="text-align: center;">
            <el-alert
              title="提示"
              :description="`当前文件类型不支持在线预览，请下载后查看。`"
              type="info"
              show-icon
            />
            <el-button type="primary" style="margin-top: 20px;"
                       @click="handleDownloadSOP({sopUrl: previewDialog.fileUrl, sopName: previewDialog.fileName})">
              下载文件
            </el-button>
          </div>
        </div>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="previewDialog.open = false">关闭</el-button>
      </div>
    </el-dialog>

    <!-- 质检方案选择弹窗 -->
    <el-dialog :title="`选择${getQualityTypeName(currentQualityType)}方案`" :visible.sync="schemeDialogVisible"
               width="500px">
      <div class="scheme-selection">
        <el-select v-model="schemeSearchValue" placeholder="搜索并选择质检方案" filterable remote
                   :remote-method="(query) => remoteMethodScheme(query, currentQualityType)" :loading="schemeLoading"
                   clearable
                   style="width: 100%;">
          <el-option v-for="scheme in schemeSearchResults" :key="scheme.id" :label="scheme.schemeName"
                     :value="scheme.id"/>
        </el-select>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="schemeDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="confirmSchemeSelection">确认</el-button>
      </div>
    </el-dialog>

    <!-- 添加工序节点弹窗 -->
    <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="600px" v-dialogDrag>
      <el-form ref="formRef" :model="formData" :rules="formRules" label-width="auto">
        <el-form-item label="选择工序" prop="procedureId">
          <el-select v-model="formData.procedureId" placeholder="请选择工序" filterable remote :remote-method="remoteMethod"
                     :loading="loadingProcedure" clearable @change="handleProcedureChange" style="width: 100%">
            <el-option v-for="procedure in procedureList" :key="procedure.id"
                       :label="procedure.procedureCode + '-' + procedure.procedureName" :value="procedure.id"/>
          </el-select>
        </el-form-item>
        <el-form-item label="工艺节点名称" prop="processNodeName">
          <el-input v-model="formData.processNodeName" placeholder="请输入工艺节点名称"/>
        </el-form-item>
        <el-form-item label="自定义批次号" prop="useInputBatch">
          <el-switch v-model="formData.useInputBatch" active-text="是" inactive-text="否"/>
        </el-form-item>
        <el-form-item label="上道工序产出" prop="validateInput">
          <el-switch v-model="formData.validateInput" active-text="是" inactive-text="否"/>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="submitForm">保存</el-button>
      </div>
    </el-dialog>


  </div>
</template>

<script>
import * as ProcessRouteProcessNodeApi from '@/api/basic/processrouteprocessnode';
import * as ProcedureApi from '@/api/basic/procedure';
import * as ProcessRouteProcessNodeMaterialApi from '@/api/basic/processrouteprocessnodematerial';
import * as MaterialApi from '@/api/basic/material';

import * as ProcessRouteProcessNodeQualityApi from '@/api/basic/processrouteprocessnodequality/index.js';
import * as InspectionSchemeApi from '@/api/quality/inspectionscheme/index.js';

import Treeselect from '@riophae/vue-treeselect';
import '@riophae/vue-treeselect/dist/vue-treeselect.css';
import * as WarehouseApi from '@/api/storage/warehouse';
import * as LocationApi from '@/api/storage/location';
import {getAccessToken} from "@/utils/auth";
import VueOfficeDocx from '@vue-office/docx';
import '@vue-office/docx/lib/index.css';
import VueOfficeExcel from '@vue-office/excel';
import '@vue-office/excel/lib/index.css';
import VueOfficePdf from '@vue-office/pdf';
import pdf from 'vue-pdf';

export default {
  name: 'ProcessRouteConfig',
  data() {
    return {
      // Excel加载状态
      excelLoading: false,
      // 加载状态
      loading: false,
      loadingProcedure: false,
      // 工艺路线ID
      processRouteId: '',
      // 工序节点列表
      nodeList: [],
      // 选中的节点
      selectedNode: null,
      // 弹窗标题
      dialogTitle: '添加工序节点',
      // 当前编辑的节点ID
      editingNodeId: null,
      // 当前激活的Tab
      activeTab: 'material',
      // 库位列表
      locationList: [],
      // 物料数据
      materialData: {
        processNodeId: '',
        storageId: null,
        warehouseId: null,
        storeName: '',
        passRate: 0,
        inMaterialList: [],
        outMaterial: {
          materialId: null,
          materialNo: null,
          materialName: null,
          convertedRate: null,
          quantity: null,
          remark: null
        }
      },
      // 质检数据
      qualityData: {
        processRouteNodeId: null,
        firstCheck: false,
        lastCheck: false,
        finishedCheck: false,
        scheduleCheck: false,
        firstQualityList: [],
        lastQualityList: [],
        finishedQualityList: [],
        scheduleQualityList: []
      },

      // SOP数据
      sopData: [],
      // 上传相关
      upload: {
        open: false, // 是否显示弹出层
        title: "上传SOP文件",
        isUploading: false,
        url: process.env.VUE_APP_BASE_API + "/admin-api/infra/file/upload", // 文件上传地址
        headers: {Authorization: "Bearer " + getAccessToken()} // 设置上传的请求头部
      },
      // 预览对话框
      previewDialog: {
        open: false,
        title: '文件预览',
        fileUrl: '',
        fileName: ''
      },
      // embed标签错误状态
      embedError: false,
      // 文本文件内容
      previewContent: '',
      // Word加载状态
      wordLoading: false,
      // 文件预览方法
      previewFile(fileUrl, fileName) {
        // 重置加载状态
        this.wordLoading = false;
        this.excelLoading = false;
        this.previewContent = '';

        // 设置预览信息
        this.previewDialog.fileUrl = fileUrl;
        this.previewDialog.fileName = fileName;

        // 根据文件类型进行不同处理
        if (this.isTextPreview(fileUrl)) {
          this.loadTextContent(fileUrl);
        }

        // 打开预览对话框
        this.previewDialog.open = true;
      },
      // SOP表单数据
      sopForm: {
        sopName: '',
        remark: ''
      },
      // 表单验证规则
      sopRules: {
        sopName: [{required: true, message: '请输入文件名称', trigger: 'blur'}]
      },
      // 质检方案选择相关
      currentQualityType: '',
      schemeSearchResults: [], // 质检方案搜索结果
      schemeSearchValue: '', // 搜索框值
      schemeLoading: false,
      schemeDialogVisible: false, // 质检方案选择弹窗显示状态
      schemeQuery: {
        pageNo: 1,
        pageSize: 100,
        schemeType: '',
        schemeName: '' // 添加schemeName搜索字段
      },

      // 仓库树数据
      warehouseTree: [],
      // 仓库树加载状态
      treeLoading: false,
      // 物料选择列表
      materialList: [],
      // 加载状态
      loadingMaterial: false,
      // 质检加载状态
      loadingQuality: false,
      // 保存中状态
      saving: false,
      // 弹窗显示状态
      dialogVisible: false,
      // 工序列表
      procedureList: [],
      // 表单数据
      formData: {
        procedureId: undefined,
        procedureCode: undefined,
        procedureName: undefined,
        processNodeName: undefined
      },
      // 表单验证
      formRules: {
        procedureId: [{required: true, message: '请选择工序', trigger: 'change'}],
        processNodeName: [{required: true, message: '请输入工艺节点名称', trigger: 'blur'}]
      }
    };
  },
  components: {
    ElUpload: require('element-ui/lib/upload').default,
    Treeselect,
    pdf,
    VueOfficeExcel,
    VueOfficeDocx
  },
  created() {
    // 从JS原生localStorage获取工艺路线ID
    this.processRouteId = localStorage.getItem('processRouteId');
    // 只在created中调用一次getNodeList
    this.getNodeList();
    // 获取仓库树数据
    this.getWarehouseTree();
    // 页面加载时默认获取物料列表
    this.getMaterialList();
  },
  watch: {
    // 监听工艺路线ID变化，仅当ID发生实际变化时才重新加载数据
    'processRouteId': {
      handler(newVal, oldVal) {
        if (newVal && newVal !== oldVal) {
          this.getNodeList();
        }
      }
    }
  },
  methods: {
    /** 仓库选择变化时触发 */
    async onWarehouseChange(warehouseId, noClearn) {
      if (!noClearn) {
        this.materialData.warehouseLocationId = null;
      }
      if (warehouseId) {
        await this.getLocationList(warehouseId.id);
      } else {
        this.locationList = [];
      }
    },
    /** 根据仓库ID获取库位列表 */
    async getLocationList(warehouseId) {
      try {
        const params = {
          pageNo: 1,
          pageSize: 100,
          warehouseId: warehouseId
        };
        const res = await LocationApi.getLocationPage(params);
        this.locationList = res.data.list;
      } catch (error) {
        console.error('获取库位列表失败:', error);
        this.locationList = [];
      }
    },
    /** 获取工序节点列表 */
    async getNodeList() {
      this.loading = true;
      try {
        const res = await ProcessRouteProcessNodeApi.getNodeAll({
          processRouteId: this.processRouteId,
          id: this.processRouteId

        });
        this.nodeList = res.data || [];

        // 如果节点列表不为空，默认选择第一个节点
        if (this.nodeList && this.nodeList.length > 0 && !this.selectedNode) {
          this.selectNode(this.nodeList[0]);
        }
      } catch (error) {
        this.$modal.msgError('获取工序节点列表失败');
      } finally {
        this.loading = false;
      }
    },

    /** 显示添加弹窗 */
    showAddDialog() {
      this.resetForm();
      this.dialogTitle = '添加工序节点';
      this.remoteMethod('');
      this.dialogVisible = true;
    },

    /** 处理编辑操作 */
    handleEdit(node) {
      this.resetForm();
      this.dialogTitle = '修改工序节点';
      this.editingNodeId = node.id;
      this.formData = {
        id: node.id,
        procedureId: node.procedureId,
        procedureCode: node.procedureCode,
        procedureName: node.procedureName,
        processNodeName: node.processNodeName,
        useInputBatch: !!node.useInputBatch,
        validateInput: !!node.validateInput
      };
      // 预先加载工序列表，确保选择器中有数据
      this.getProcedureList();
      this.dialogVisible = true;
    },

    /** 重置表单 */
    resetForm() {
      this.formData = {
        id: undefined,
        procedureId: undefined,
        procedureCode: undefined,
        procedureName: undefined,
        processNodeName: undefined,
        useInputBatch: false,
        validateInput: false
      };
      this.editingNodeId = null;
      if (this.$refs.formRef) {
        this.$refs.formRef.resetFields();
      }
    },
    /** 获取仓库树数据 */
    async getWarehouseTree() {
      try {
        this.treeLoading = true;
        const params = {
          pageNo: 1,
          pageSize: 1000 // 获取足够多的数据用于构建树
        };
        const res = await WarehouseApi.getWarehousePage(params);
        this.warehouseTree = res.data;
      } catch (error) {
        console.error('获取仓库树数据失败:', error);
        this.$modal.msgError('获取仓库树数据失败');
      } finally {
        this.treeLoading = false;
      }
    },
    /** 树节点标准化处理 */
    normalizerW(node) {
      const result = {
        id: node.id,
        label: node.warehouseName,
        children: undefined
      };
      // 只有当children存在且不为undefined且长度大于0时才添加该字段
      if (node.children && node.children.length > 0) {
        result.children = node.children;
      }
      return result;
    },
    /** 获取仓库树数据 */
    async getWarehouseTree() {
      try {
        this.treeLoading = true;
        const params = {
          pageNo: 1,
          pageSize: 1000 // 获取足够多的数据用于构建树
        };
        const res = await WarehouseApi.getWarehousePage(params);
        this.warehouseTree = res.data;
      } catch (error) {
        console.error('获取仓库树数据失败:', error);
        this.$modal.msgError('获取仓库树数据失败');
      } finally {
        this.treeLoading = false;
      }
    },
    /** 远程搜索工序 */
    async remoteMethod(query) {
      if (!query) {
        // 如果查询条件为空，加载默认工序列表
        this.getProcedureList();
        return;
      }

      this.loadingProcedure = true;
      try {
        const params = {
          pageNo: 1,
          pageSize: 100,
          procedureName: query
        };
        const res = await ProcedureApi.getProcedurePage(params);
        this.procedureList = res.data?.list || [];
      } catch (error) {
        console.error('远程搜索工序失败:', error);
      } finally {
        this.loadingProcedure = false;
      }
    },

    /** 获取工序列表 */
    async getProcedureList() {
      try {
        const res = await ProcedureApi.getProcedurePage({
          pageNo: 1,
          pageSize: 100
        });
        this.procedureList = res.data?.list || [];
      } catch (error) {
        console.error('获取工序列表失败:', error);
      }
    },

    /** 处理工序选择 */
    handleProcedureChange(procedureId) {
      const selectedProcedure = this.procedureList.find(p => p.id === procedureId);
      if (selectedProcedure) {
        this.formData.procedureCode = selectedProcedure.procedureCode;
        this.formData.procedureName = selectedProcedure.procedureName;
      } else {
        this.formData.procedureCode = undefined;
        this.formData.procedureName = undefined;
      }
    },

    /** 提交表单 */
    async submitForm() {
      await this.$refs.formRef.validate();

      const data = {
        id: this.formData.id,
        processRouteId: this.processRouteId,
        procedureId: this.formData.procedureId,
        procedureCode: this.formData.procedureCode,
        procedureName: this.formData.procedureName,
        processNodeName: this.formData.processNodeName,
        useInputBatch: this.formData.useInputBatch,
        validateInput: this.formData.validateInput
      };

      try {
        if (this.editingNodeId) {
          // 更新操作
          await ProcessRouteProcessNodeApi.updateProcessRouteProcessNode(data);
          this.$modal.msgSuccess('修改成功');
        } else {
          // 添加操作
          await ProcessRouteProcessNodeApi.createProcessRouteProcessNode(data);
          this.$modal.msgSuccess('添加成功');
        }
        this.dialogVisible = false;
        this.getNodeList();
      } catch (error) {
        this.$modal.msgError(this.editingNodeId ? '修改失败' : '添加失败');
      }
    },

    /** 选择节点 */
    selectNode(node) {
      this.selectedNode = node;
      // 切换到物料标签页
      this.activeTab = 'material';
      // 加载物料数据
      if (node && node.id) {
        this.getMaterialData(node.id);
        this.getQualityData(node.id);
        this.getSOPData(node.id);
      }
    },
    /** 获取质检数据 */
    async getQualityData(nodeId) {
      this.loadingQuality = true;
      try {
        const response = await ProcessRouteProcessNodeQualityApi.getQualityAllByNodeId({nodeId});
        if (response.code === 0 && response.data) {
          // 使用$set确保响应式更新
          this.$set(this, 'qualityData', {
            ...response.data,
            // 确保所有数组属性存在
            firstQualityList: response.data.firstQualityList || [],
            lastQualityList: response.data.lastQualityList || [],
            finishedQualityList: response.data.finishedQualityList || [],
            scheduleQualityList: response.data.scheduleQualityList || []
          });
        } else {
          // 如果获取失败，使用默认值
          this.$set(this, 'qualityData', {
            processRouteNodeId: nodeId,
            firstCheck: false,
            lastCheck: false,
            finishedCheck: false,
            scheduleCheck: false,
            firstQualityList: [],
            lastQualityList: [],
            finishedQualityList: [],
            scheduleQualityList: []
          });
        }
      } catch (error) {
        console.error('获取质检数据失败:', error);
        // 发生错误时使用默认值
        this.$set(this, 'qualityData', {
          processRouteNodeId: nodeId,
          firstCheck: false,
          lastCheck: false,
          finishedCheck: false,
          scheduleCheck: false,
          firstQualityList: [],
          lastQualityList: [],
          finishedQualityList: [],
          scheduleQualityList: []
        });
        this.$message.error('获取质检数据失败，请重试');
      } finally {
        this.loadingQuality = false;
      }
    },


    /** 保存质检配置 */
    async saveQualityConfig() {
      if (!this.selectedNode || !this.selectedNode.id) {
        this.$message.warning('请先选择工序节点');
        return;
      }

      this.saving = true;
      try {
        // 确保processRouteNodeId正确设置
        this.qualityData.processRouteNodeId = this.selectedNode.id;

        // 调用保存质检配置的API
        const response = await ProcessRouteProcessNodeQualityApi.updateProcessRouteProcessNodeQuality(this.qualityData);

        if (response.code === 0) {
          this.$message.success('保存成功');
        } else {
          this.$message.error(response.msg || '保存失败');
        }
      } catch (error) {
        console.error('保存质检配置失败:', error);
        this.$message.error('保存失败');
      } finally {
        this.saving = false;
      }
    },

    /** 切换质检类型开关 */
    async toggleQualityType(type) {
      // 使用Vue的$set方法确保响应式更新
      this.$set(this.qualityData, type, this.qualityData[type]);

      // 立即调用update方法保存变更
      await this.updateQualityConfig();
    },

    /** 获取质检类型名称 */
    getQualityTypeName(type) {
      const typeMap = {
        firstCheck: '首件检',
        lastCheck: '末件检',
        finishedCheck: '完工检',
        scheduleCheck: '巡检'
      };
      return typeMap[type] || '';
    },

    /** 删除质检方案 */
    async deleteQualityScheme(type, schemeId) {
      try {
        const schemeListMap = {
          firstCheck: 'firstQualityList',
          lastCheck: 'lastQualityList',
          finishedCheck: 'finishedQualityList',
          scheduleCheck: 'scheduleQualityList'
        };

        const listKey = schemeListMap[type];
        if (!listKey || !this.qualityData[listKey]) return;

        // 使用$set确保响应式更新
        const filteredList = this.qualityData[listKey].filter(
          item => item.inspectionSchemeId !== schemeId
        );
        this.$set(this.qualityData, listKey, filteredList);

        // 立即调用update方法保存变更
        await this.updateQualityConfig();
      } catch (error) {
        console.error('删除质检方案失败:', error);
        this.$message.error('删除失败');
      }
    },


    /** 更新质检配置 */
    async updateQualityConfig() {
      if (!this.selectedNode || !this.selectedNode.id) {
        this.$message.warning('请先选择工序节点');
        return;
      }

      try {
        // 确保processRouteNodeId正确设置
        this.qualityData.processRouteNodeId = this.selectedNode.id;

        // 调用更新接口，提交所有质检数据
        this.loadingQuality = true;
        const response = await ProcessRouteProcessNodeQualityApi.updateProcessRouteProcessNodeQuality(this.qualityData);

        if (response.code === 0) {
          this.$message.success('保存成功');

        } else {
          // 移除失败后的额外提醒，让接口自行处理错误
          throw new Error(response.msg || '保存失败');
        }
        this.getQualityData(this.selectedNode.id);

      } catch (error) {
        console.error('更新质检配置失败:', error);
        // 保存失败时重新获取质检相关信息
        await this.getQualityData(this.selectedNode.id);
      } finally {
        this.loadingQuality = false;
      }
    },

    // 打开质检方案选择弹窗
    focusSchemeSelect(qualityType) {
      if (!this.selectedNode || !this.selectedNode.id) {
        this.$message.warning('请先选择工序节点');
        return;
      }

      this.currentQualityType = qualityType;
      this.schemeSearchValue = '';
      // 立即加载该类型的质检方案列表
      this.remoteMethodScheme('', qualityType);
      // 打开弹窗
      this.schemeDialogVisible = true;
    },


    // 弹窗中确认选择质检方案
    async confirmSchemeSelection() {
      if (!this.schemeSearchValue) {
        this.$message.warning('请选择质检方案');
        return;
      }

      // 查找选中的方案
      const selectedScheme = this.schemeSearchResults.find(scheme => scheme.id === this.schemeSearchValue);
      if (!selectedScheme) {
        this.$message.warning('未找到选中的质检方案');
        return;
      }

      const schemeListMap = {
        firstCheck: 'firstQualityList',
        lastCheck: 'lastQualityList',
        finishedCheck: 'finishedQualityList',
        scheduleCheck: 'scheduleQualityList'
      };

      const listKey = schemeListMap[this.currentQualityType];
      if (!listKey) return;

      // 确保列表存在
      if (!this.qualityData[listKey]) {
        this.$set(this.qualityData, listKey, []);
      }

      // 检查是否已存在该方案
      const existingIds = new Set(this.qualityData[listKey].map(item => item.inspectionSchemeId));
      if (!existingIds.has(selectedScheme.id)) {
        // 使用$set确保响应式更新
        this.$set(this.qualityData[listKey], this.qualityData[listKey].length, {
          inspectionSchemeId: selectedScheme.id,
          inspectionSchemeName: selectedScheme.schemeName,
          inspectionType: this.currentQualityType
        });

        // 立即调用update方法保存所有质检数据
        await this.updateQualityConfig();

        // 关闭弹窗
        this.schemeDialogVisible = false;
        this.schemeSearchValue = '';
      } else {
        this.$message.warning('该质检方案已添加');
      }
    },

    /** 质检方案远程搜索方法 */
    async remoteMethodScheme(query, type) {
      if (!query && type) {
        // 如果是首次加载且提供了类型，获取该类型的所有方案
        const schemeTypeMap = {
          firstCheck: 1,
          lastCheck: 2,
          finishedCheck: 3,
          scheduleCheck: 4
        };
        this.schemeQuery.schemeType = schemeTypeMap[type] || '';
        this.schemeQuery.schemeName = '';
      } else {
        // 搜索时使用查询词
        this.schemeQuery.schemeName = query;
      }

      // 保存当前操作的质检类型
      this.currentQualityType = type;

      // 加载质检方案数据
      await this.loadInspectionSchemes();
    },

    /** 添加质检方案 */
    addQualityScheme(type) {
      if (!this.selectedNode || !this.selectedNode.id) {
        this.$message.warning('请先选择工序节点');
        return;
      }

      // 保存当前质检类型并初始化搜索
      this.currentQualityType = type;
      this.schemeSearchResults = [];

      // 首次加载该类型的所有方案
      this.remoteMethodScheme('', type);

      // 打开下拉选择器的逻辑将由模板中的el-select处理
    },

    /** 加载质检方案 */
    async loadInspectionSchemes() {
      this.schemeLoading = true;
      try {
        const res = await InspectionSchemeApi.getInspectionSchemePage(this.schemeQuery);
        if (res.code === 0 && res.data) {
          this.schemeSearchResults = res.data.list || [];
        }
      } catch (error) {
        console.error('加载质检方案失败:', error);
      } finally {
        this.schemeLoading = false;
      }
    },

    /** 处理质检方案选择 */
    // 此方法现在仅作为内部使用，不再直接调用
    handleSchemeSelect(schemeId, type) {
      if (!schemeId) return;

      // 查找选中的方案
      const selectedScheme = this.schemeSearchResults.find(scheme => scheme.id === schemeId);
      if (!selectedScheme) {
        return;
      }

      const schemeListMap = {
        firstCheck: 'firstQualityList',
        lastCheck: 'lastQualityList',
        finishedCheck: 'finishedQualityList',
        scheduleCheck: 'scheduleQualityList'
      };

      const listKey = schemeListMap[type];
      if (!listKey) return;

      // 确保列表存在
      if (!this.qualityData[listKey]) {
        this.$set(this.qualityData, listKey, []);
      }

      // 检查是否已存在该方案
      const existingIds = new Set(this.qualityData[listKey].map(item => item.inspectionSchemeId));
      if (!existingIds.has(selectedScheme.id)) {
        // 使用$set确保响应式更新
        this.$set(this.qualityData[listKey], this.qualityData[listKey].length, {
          id: null,
          inspectionSchemeId: selectedScheme.id,
          inspectionSchemeName: selectedScheme.schemeName,
          inspectionType: type
        });

        // 清空选择器，以便继续添加
        this.schemeSearchValue = '';
      }
    },


    /** 获取物料数据 */
    async getMaterialData(nodeId) {
      this.loadingMaterial = true;
      try {
        const res = await ProcessRouteProcessNodeMaterialApi.getMaterialAllByNodeId({nodeId});
        if (res.code === 0 && res.data) {
          this.materialData = res.data;
          if (!res.data.outMaterial) {
            this.materialData.outMaterial = {
              materialId: null,
              materialNo: null,
              materialName: null,
              convertedRate: null,
              quantity: null,
              remark: null
            };
          } else {
            if (res.data.outMaterial.materialName) {
              await this.getMaterialList(res.data.outMaterial.materialName);
            }
          }
          // 遍历inMaterialList，使用每行的materialName调用对应行的getMaterialList方法
          if (this.materialData.inMaterialList && this.materialData.inMaterialList.length > 0) {
            for (let i = 0; i < this.materialData.inMaterialList.length; i++) {
              const material = this.materialData.inMaterialList[i];
              if (material.materialName) {
                await this.getMaterialList(material.materialName, i);
              } else {
                // 为没有materialName的行获取默认物料列表
                await this.getMaterialList('', i);
              }
            }
          }
          if (this.materialData.warehouseId) {
            this.onWarehouseChange(this.materialData.warehouseId, true)
          }
        } else {
          // 初始化空数据
          this.materialData = {
            processNodeId: nodeId,
            warehouseId: '',
            warehouseLocationId: '',
            storeName: '',
            passRate: 0,
            inMaterialList: [],
            outMaterial: {
              materialId: null,
              materialNo: null,
              materialName: null,
              convertedRate: null,
              quantity: null,
              remark: null
            }
          };
        }
      } catch (error) {
        this.$modal.msgError('获取物料数据失败');
      } finally {
        this.loadingMaterial = false;
      }
    },

    /** 获取物料选择列表 */
    async getMaterialList(query = '', index = null) {
      try {
        const res = await MaterialApi.getMaterialPage({
          pageNo: 1,
          pageSize: 100,
          materialName: query
        });

        // 如果提供了索引，为特定物料项设置列表
        if (index !== null && this.materialData.inMaterialList && this.materialData.inMaterialList[index]) {
          this.$set(this.materialData.inMaterialList[index], 'materialOptions', res.data?.list || []);
        } else {
          // 否则更新全局物料列表
          this.materialList = res.data?.list || [];
        }
      } catch (error) {
        console.error('获取物料列表失败:', error);
      }
    },

    /** 添加投入物料 */
    addInMaterial() {
      if (!this.materialData.inMaterialList) {
        this.materialData.inMaterialList = [];
      }
      const newMaterial = {
        id: null,
        materialId: '',
        materialNo: '',
        materialName: '',
        convertedRate: 0,
        isMaster: false,
        materialOptions: [] // 为每个物料项添加独立的选项列表
      };
      this.materialData.inMaterialList.push(newMaterial);
      // 为新添加的物料项获取物料列表
      const index = this.materialData.inMaterialList.length - 1;
      this.getMaterialList('', index);
    },

    /** 删除投入物料 */
    removeInMaterial(index) {
      this.materialData.inMaterialList.splice(index, 1);
    },

    /** 处理主物料选择变化 */
    handleMasterChange(currentRow, index) {
      // 如果当前行被设置为主物料
      if (currentRow.isMaster) {
        // 将其他所有行的主物料状态设置为false
        this.materialData.inMaterialList.forEach((row, idx) => {
          if (idx !== index) {
            row.isMaster = false;
          }
        });
      }
    },

    /** 处理物料选择 */
    handleMaterialSelect(materialId, type, index = null) {
      const selectedMaterial = this.materialList.find(m => m.id === materialId);
      if (!selectedMaterial) return;

      if (type === 'in') {
        if (this.materialData.inMaterialList[index]) {
          this.materialData.inMaterialList[index].materialNo = selectedMaterial.materialNo;
          this.materialData.inMaterialList[index].materialName = selectedMaterial.materialName;
        }
      } else if (type === 'out') {
        // 确保outMaterial对象存在
        if (!this.materialData.outMaterial) {
          this.materialData.outMaterial = {};
        }
        // 设置所有必要的属性
        this.materialData.outMaterial.materialId = materialId; // 确保materialId被正确设置
        this.materialData.outMaterial.materialNo = selectedMaterial.materialNo;
        this.materialData.outMaterial.materialName = selectedMaterial.materialName;
      }
    },

    /** 初始化产出物料 */
    initOutMaterial() {
      if (!this.materialData.outMaterial) {
        this.materialData.outMaterial = {
          id: null,
          materialId: '',
          materialNo: '',
          materialName: '',
          convertedRate: 0,
          isMaster: true
        };
      }
    },

    /** 保存物料配置 */
    async saveMaterialConfig() {
      // 验证数据
      if (!this.selectedNode || !this.selectedNode.id) {
        this.$modal.msgWarning('请先选择工序节点');
        return;
      }

      // 准备提交数据
      const submitData = {
        processNodeId: this.materialData.processNodeId,
        warehouseId: this.materialData.warehouseId,
        storageId: this.materialData.storageId,
        passRate: Number(this.materialData.passRate) || 0,
        inMaterialList: (this.materialData.inMaterialList || []).map(item => ({
          id: item.id,
          materialId: item.materialId,
          convertedRate: Number(item.convertedRate) || 0,
          isMaster: item.isMaster || false
        })),
        outMaterial: this.materialData.outMaterial ? {
          id: this.materialData.outMaterial.id,
          materialId: this.materialData.outMaterial.materialId,
          convertedRate: Number(this.materialData.outMaterial.convertedRate) || 0,
        } : null
      };

      this.saving = true;
      try {
        // 这里需要根据实际的保存接口进行调整
        await ProcessRouteProcessNodeMaterialApi.updateProcessRouteProcessNodeMaterial(submitData);
        await this.getMaterialData(this.selectedNode.id);

      } catch (error) {
      } finally {
        this.saving = false;
      }
    },

    /** 删除工序节点 */
    async handleDelete(id) {
      await this.$modal.confirm('是否确认删除该工序节点？');
      try {
        await ProcessRouteProcessNodeApi.deleteProcessRouteProcessNode(id);
        this.$modal.msgSuccess('删除成功');
        await this.getNodeList();
      } catch (error) {
        this.$modal.msgError('删除失败');
      }
    },

    /** 处理SOP上传 */
    handleUploadSOP() {
      if (!this.selectedNode) {
        this.$modal.msgWarning('请先选择工序节点');
        return;
      }
      // 重置表单
      this.resetSopForm();
      this.upload.open = true;
    },

    /** 重置SOP表单 */
    resetSopForm() {
      this.sopForm = {
        sopName: '',
        remark: ''
      };
      this.$refs.sopForm && this.$refs.sopForm.resetFields();
      this.$refs.upload && this.$refs.upload.clearFiles();
    },


    /** 处理文件上传进度 */
    handleFileUploadProgress(event, file, fileList) {
      this.upload.isUploading = true;
    },

    /** 提交SOP表单 */
    submitSopForm() {
      this.$refs.sopForm.validate((valid) => {
        if (valid && this.$refs.upload.uploadFiles.length > 0) {
          // 使用el-upload组件的submit方法直接提交
          this.$refs.upload.submit();
        } else if (this.$refs.upload.uploadFiles.length === 0) {
          this.$modal.msgWarning('请选择要上传的文件');
        }
      });
    },

    /** 文件上传成功处理 */
    async handleFileSuccess(response, file, fileList) {
      try {
        if (response.code === 0 && response.data) {
          // 获取文件上传后的路径，然后调用createSOP接口
          // 创建新的SOP项
          const newSopItem = {
            "processRouteId": this.processRouteId,
            "processRouteNodeId": this.selectedNode.id,
            "sopName": this.sopForm.sopName,
            "sopUrl": response.data,
            "remark": this.sopForm.remark,
            "sort": 0
          };

          // 将现有SOP数据也包含进来，保留已有文件
          const existingSopItems = (this.sopData || []).map(item => ({
            "id": item.id,
            "processRouteId": item.processRouteId || this.processRouteId,
            "processRouteNodeId": item.processRouteNodeId,
            "sopName": item.sopName,
            "sopUrl": item.sopUrl,
            "remark": item.remark,
            "sort": item.sort || 0
          }));

          // 组合新旧数据
          const data = {
            "processRouteNodeId": this.selectedNode.id,
            "sopList": [...existingSopItems, newSopItem]
          };

          // 调用创建SOP接口
          const res = await ProcessRouteProcessNodeQualityApi.createSOP(data);
          if (res.code === 0) {
            // 清理
            this.upload.open = false;
            this.upload.isUploading = false;
            this.$refs.upload.clearFiles();
            // 提示成功，并刷新SOP列表
            this.$modal.msgSuccess('上传成功');
            this.getSOPData(this.selectedNode.id);
          } else {
            this.$modal.msgError(res.msg || '创建SOP记录失败');
            this.upload.isUploading = false;
          }
        } else {
          this.$modal.msgError(response.msg || '文件上传失败');
          this.upload.isUploading = false;
        }
      } catch (error) {
        console.error('处理SOP上传失败:', error);
        this.$modal.msgError('上传失败');
        this.upload.isUploading = false;
      }
    },

    /** 处理SOP下载 */
    handleDownloadSOP(row) {
      if (row.sopUrl) {
        window.open(row.sopUrl, '_blank');
      } else {
        this.$modal.msgWarning('文件不存在');
      }
    },

    /** 预览SOP */
    async handlePreviewSOP(row) {
      // 检查是否为完整URL
      let fileUrl = row.sopUrl;
      // if (!fileUrl.startsWith('http://') && !fileUrl.startsWith('https://')) {
      //   // 如果不是完整URL，添加API前缀
      //   fileUrl = process.env.VUE_APP_BASE_API + fileUrl;
      // }

      // 设置预览对话框信息
      this.previewDialog.fileName = row.sopName;
      this.previewDialog.fileUrl = fileUrl;

      // 根据文件类型进行不同处理
      if (this.isTextPreview(fileUrl)) {
        await this.loadTextContent(fileUrl);
      } else {
        // 清空之前的文本内容
        this.previewContent = '';
      }

      // 打开预览对话框
      this.previewDialog.open = true;
    },

    /** 获取文件URL（移除preview参数，让vue-office-excel组件直接处理） */
    getPreviewUrl(fileUrl) {
      // 直接返回原始URL，vue-office-excel组件会自行处理
      return fileUrl;
    },

    /** 处理SOP删除 */
    handleDeleteSOP(row) {
      this.$modal.confirm(`是否确认删除SOP文件"${row.sopName}"?`).then(async () => {
        try {
          // 先从本地数据中移除要删除的项
          this.sopData = this.sopData.filter(item => item.id !== row.id);

          // 准备数据调用保存接口
          const existingSopItems = (this.sopData || []).map(item => ({
            "id": item.id,
            "processRouteId": item.processRouteId || this.processRouteId,
            "processRouteNodeId": item.processRouteNodeId,
            "sopName": item.sopName,
            "sopUrl": item.sopUrl,
            "remark": item.remark,
            "sort": item.sort || 0
          }));

          // 组合数据
          const data = {
            "processRouteNodeId": this.selectedNode.id,
            "sopList": existingSopItems
          };

          // 调用保存接口
          const res = await ProcessRouteProcessNodeQualityApi.createSOP(data);
          if (res.code === 0) {
            this.$modal.msgSuccess('删除成功');
          } else {
            this.$modal.msgError(res.msg || '删除失败');
            // 恢复数据以保证一致性
            this.getSOPData(this.selectedNode.id);
          }
        } catch (error) {
          console.error('删除SOP失败:', error);
          this.$modal.msgError('删除失败');
          // 恢复数据以保证一致性
          this.getSOPData(this.selectedNode.id);
        }
      }).catch(() => {
      });
    },


    /** 判断是否为图片文件 */
    isImagePreview(fileUrl) {
      if (!fileUrl) return false;
      const extension = fileUrl.split('.').pop().toLowerCase();
      const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'];
      return imageExtensions.includes(extension);
    },

    /** 判断是否为PDF文件 */
    isPdfPreview(fileUrl) {
      if (!fileUrl) return false;
      const extension = fileUrl.split('.').pop().toLowerCase();
      return extension === 'pdf';
    },

    /** 判断是否为Word文件 */
    isWordPreview(fileUrl) {
      if (!fileUrl) return false;
      const extension = fileUrl.split('.').pop().toLowerCase();
      return ['doc', 'docx'].includes(extension);
    },

    /** 判断是否为Excel文件 */
    isExcelPreview(fileUrl) {
      if (!fileUrl) return false;
      const extension = fileUrl.split('.').pop().toLowerCase();
      return ['xls', 'xlsx'].includes(extension);
    },

    /** 处理嵌入错误 */
    handleEmbedError() {
      console.warn('嵌入预览失败，尝试使用iframe后备方案');
      this.embedError = true;
    },

    /** 处理PDF页面数量变化 */
    handlePdfNumPages(numPages) {
      console.log('PDF总页数:', numPages);
    },

    /** 处理PDF页面加载 */
    handlePdfPageLoaded(page) {
      console.log('PDF页面加载完成:', page);
    },

    /** 处理PDF加载完成 */
    handlePdfLoaded() {
      console.log('PDF加载完成');
    },

    /** Excel渲染完成回调 */
    renderedHandler() {
      console.log('Excel文件渲染完成');
      this.excelLoading = false;
    },

    /** Excel错误处理 */
    errorHandler(error) {
      console.error('Excel文件渲染失败:', error);
      this.$message.error('Excel文件加载失败，请检查文件格式是否正确');
    },

    /** 判断是否为Word文件 */
    isWordPreview(fileUrl) {
      if (!fileUrl) return false;
      const extension = fileUrl.split('.').pop().toLowerCase();
      return ['doc', 'docx'].includes(extension);
    },

    /** 判断是否为Excel文件 */
    isExcelPreview(fileUrl) {
      if (!fileUrl) return false;
      const extension = fileUrl.split('.').pop().toLowerCase();
      return ['xls', 'xlsx'].includes(extension);
    },

    /** 判断是否为文本文件 */
    isTextPreview(fileUrl) {
      if (!fileUrl) return false;
      const extension = fileUrl.split('.').pop().toLowerCase();
      const textExtensions = ['txt', 'log', 'csv', 'md', 'json', 'xml', 'html', 'css', 'js'];
      return textExtensions.includes(extension);
    },

    /** PDF渲染完成事件 */
    handlePdfRendered() {
      console.log('PDF渲染完成');
    },

    /** PDF渲染错误事件 */
    handlePdfError(error) {
      console.error('PDF渲染错误:', error);
      this.$modal.msgError('PDF文件加载失败，请尝试下载查看');
    },

    /** Word加载开始事件 */
    handleDocxLoad() {
      console.log('Word文件开始加载');
      this.wordLoading = true;
    },

    /** Word渲染完成事件 */
    handleDocxRendered() {
      console.log('Word渲染完成');
      this.wordLoading = false;
    },

    /** Word渲染错误事件 */
    handleDocxError(error) {
      console.error('Word渲染错误:', error);
      this.wordLoading = false;
      this.$modal.msgError(`Word文件加载失败: ${error.message || '未知错误'}`);
    },

    /** Excel渲染完成事件 */
    handleExcelRendered() {
      console.log('Excel渲染完成');
    },

    /** Excel渲染错误事件 */
    handleExcelError(error) {
      console.error('Excel渲染错误:', error);
      this.$modal.msgError('Excel文件加载失败，请尝试下载查看');
    },

    /** 加载文本文件内容 */
    async loadTextContent(fileUrl) {
      try {
        // 使用fetch API加载文本内容，添加Authorization头
        const response = await fetch(fileUrl, {
          headers: {
            'Authorization': 'Bearer ' + getAccessToken(),
            'Accept': 'text/plain, text/html, text/csv, application/json, application/xml'
          }
        });

        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }

        // 根据文件扩展名决定如何处理内容
        const contentType = response.headers.get('content-type');
        let content;

        if (contentType && contentType.includes('json')) {
          // 尝试解析JSON并美化
          const jsonData = await response.json();
          content = JSON.stringify(jsonData, null, 2);
        } else {
          // 其他情况直接获取文本
          content = await response.text();
        }

        this.previewContent = content;
      } catch (error) {
        console.error('加载文本内容失败:', error);
        this.previewContent = `加载失败: ${error.message}`;
      }
    },

    /** 获取SOP数据 */
    async getSOPData(id) {
      try {
        const res = await ProcessRouteProcessNodeQualityApi.getSOPAllByNodeId({nodeId: id});
        this.sopData = [];
        if (res.code === 0 && res.data) {
          this.sopData = res.data.sopList || [];
        }
      } catch (error) {
        console.error('获取SOP数据失败:', error);
        this.$modal.msgError('获取SOP数据失败');
      }
    }
  }
};
</script>

<style scoped>
.config-container {
  display: flex;
  height: calc(100vh - 200px);
  gap: 20px;
}

.left-panel {
  width: 400px;
  border: 1px solid #e6e6e6;
  border-radius: 4px;
  display: flex;
  flex-direction: column;
}

.right-panel {
  flex: 1;
  border: 1px solid #e6e6e6;
  border-radius: 4px;
  padding: 20px;
}

.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 15px;
  border-bottom: 1px solid #e6e6e6;
  background-color: #f5f7fa;
}

.panel-header span {
  font-weight: bold;
  font-size: 14px;
}

.node-list-container {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
}

.node-card {
  background-color: #fff;
  border: 1px solid #e6e6e6;
  border-radius: 6px;
  padding: 12px;
  margin-bottom: 12px;
  cursor: pointer;
  transition: all 0.3s ease;
  position: relative;
}

.node-card:hover {
  border-color: #409eff;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  transform: translateY(-2px);
}

.node-card-selected {
  background-color: #ecf5ff;
  border-color: #409eff;
  box-shadow: 0 2px 12px rgba(64, 158, 255, 0.2);
}

.node-card.selected {
  border-color: #409eff;
  background-color: #ecf5ff;
}

.node-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}

.node-code {
  background-color: #f0f2f5;
  color: #606266;
  font-size: 12px;
  padding: 2px 8px;
  border-radius: 3px;
}

.delete-btn:hover {
  color: #f56c6c;
}

.node-title {
  font-weight: 500;
  color: #303133;
  margin-bottom: 4px;
  font-size: 14px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.node-description {
  font-size: 12px;
  color: #909399;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.empty-list {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 200px;
  color: #909399;
}

.empty-state {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  min-height: 300px;
}

.empty-sub {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20px 0;
  color: #909399;
}

.section-title {
  font-size: 16px;
  font-weight: bold;
  margin: 20px 0 10px 0;
  padding-bottom: 5px;
  border-bottom: 1px solid #ebeef5;
  color: #303133;
}

.material-card {
  height: 100%;
}

.material-content {
  max-height: calc(100vh - 300px);
  overflow-y: auto;
  padding: 0 10px;
}

.out-material-section {
  margin-bottom: 20px;
}

.quality-card {
  height: 100%;
  padding: 20px;
}

.quality-section {
  margin-bottom: 30px;
  border-radius: 4px;
}

.section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.section-header h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
}

.header-controls {
  display: flex;
  gap: 10px;
  align-items: center;
}
</style>
